package sf.database.meta;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sf.codegen.IEntityEnhancer;
import sf.common.SoftHashMap;
import sf.common.exception.EntityNotEnhancedException;
import sf.common.exception.SmallOrmException;
import sf.core.DBCascadeField;
import sf.core.DBField;
import sf.core.DBObject;
import sf.core.IEntity;
import sf.database.OrmConfig;
import sf.database.annotations.ColumnInfo;
import sf.database.annotations.Comment;
import sf.database.annotations.CreatedDate;
import sf.database.annotations.FetchDBField;
import sf.database.annotations.LastModifiedDate;
import sf.database.annotations.Meta;
import sf.database.annotations.SavedDefaultValue;
import sf.database.annotations.SmallEntity;
import sf.database.annotations.TableMeta;
import sf.database.annotations.Tail;
import sf.database.annotations.Type;
import sf.database.annotations.UniqueKeyGenerator;
import sf.database.dbinfo.ColumnDBType;
import sf.database.jdbc.type.Jdbcs;
import sf.database.listener.EntityListenerManager;
import sf.database.util.OrmValueUtils;
import sf.spring.asm.Attribute;
import sf.spring.asm.ClassReader;
import sf.spring.asm.ClassVisitor;
import sf.spring.asm.SpringAsmInfo;
import sf.spring.util.Assert;
import sf.spring.util.CollectionUtils;
import sf.tools.ArrayUtils;
import sf.tools.IOUtils;
import sf.tools.JavaTypeUtils;
import sf.tools.StringUtils;
import sf.tools.reflect.PropertyHold;
import sf.tools.reflect.ReflectionExtends;
import sf.tools.reflectasm.ConstructorAccess;
import sf.tools.reflectasm.MethodAccess;

import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.Convert;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinColumns;
import javax.persistence.JoinTable;
import javax.persistence.Lob;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.MapKey;
import javax.persistence.MapKeyClass;
import javax.persistence.MapKeyColumn;
import javax.persistence.MapKeyEnumerated;
import javax.persistence.MapKeyJoinColumn;
import javax.persistence.MapKeyJoinColumns;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.OrderBy;
import javax.persistence.OrderColumn;
import javax.persistence.SequenceGenerator;
import javax.persistence.SqlResultSetMapping;
import javax.persistence.SqlResultSetMappings;
import javax.persistence.Table;
import javax.persistence.TableGenerator;
import javax.persistence.Temporal;
import javax.persistence.Transient;
import javax.persistence.Version;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;

public class MetaHolder {
    private static final Logger logger = LoggerFactory.getLogger(MetaHolder.class);

    /**
     * 元数据池,对应数据库表,key必须严格的相等
     */
    protected static final Map<Class<?>, TableMapping> pool = new IdentityHashMap<>(32);

    /**
     * 维护一个软引用,降低内存消耗!不对应数据库表,只对应返回的值类.
     */
    protected static final Map<Class<?>, TableMapping> softPool = new SoftHashMap<>();

    /**
     * 数据库字段对应表
     */
    protected static final Map<DBField, ColumnMapping> dbField2Column = new ConcurrentHashMap<>();

    public static final Map<String, SqlResultSetMapping> SQL_RESULT_SET_MAPPING_MAP = new ConcurrentHashMap<>(8);

    public static boolean checkEnhancement = true;

    /**
     * 是否使用数据库字段到表的映射
     */
    public static boolean useDBField2Column = false;

    /**
     * 根据类获取表模型
     * @param clz
     * @return
     */
    public static final TableMapping getMeta(Class<?> clz) {
        Assert.notNull(clz, "");
        TableMapping m = pool.get(clz);
        if (m == null) {
            m = softPool.get(clz);
        }
        if (m == null) {
            m = initData(clz, checkEnhancement);
            if (clz.getAnnotation(Table.class) != null || clz.getAnnotation(Entity.class) != null) {
                pool.put(clz, m);
            } else {
                softPool.put(clz, m);
            }
            //暂不设置.
            //  m.setRelationalPath(new SQLRelationalPath(m));
            //处理级联
            cascade(m);
            checkCascade(m);
        }
        return m;
    }

    /**
     * 在获取类时，需要有一个标记快速判断该类是否经过增强（无论是动态增强还是静态增强）一旦发现没增强的类，就抛出异常?
     * @param clz
     * @param checkEnhancement 检查是否增强过
     * @return
     */
    public static TableMapping initData(Class<?> clz, boolean checkEnhancement) {
        TableMapping m1 = pool.get(clz);
        if (m1 != null) {
            return m1; // 双重检查锁定
        }

        if (checkEnhancement && IEntity.class.isAssignableFrom(clz) && OrmConfig.getInstance().isCheckEnhancement()) {
            SmallEntity ee = clz.getAnnotation(SmallEntity.class);
            assertEnhanced((Class<? extends IEntity>) clz, ee);
        }
        return initPojo(clz, OrmConfig.getInstance().getBeanValueType() == OrmValueUtils.BeanValueType.reflectasm);

    }

    /**
     * @param clz
     * @param useReflectasm 是否使用reflectasm
     * @return
     */
    protected static TableMapping initPojo(Class<?> clz, boolean useReflectasm) {
        List<Field> fields = new ArrayList<>();
        Method[] methods = clz.getDeclaredMethods();
        Class<?>[] subcls = clz.getDeclaredClasses();

        Collections.addAll(fields, clz.getDeclaredFields());
        //提取父类字段
        Class<?> clazz = clz.getSuperclass();
        for (; clazz != null && clazz != Object.class && clazz != DBObject.class; clazz = clazz.getSuperclass()) {
            Collections.addAll(fields, clazz.getDeclaredFields());
        }

        TableMapping meta = new TableMapping();
        //表信息处理
        handleClass(clz, subcls, meta);
        //字段处理
        handleField(meta, fields);
        //方法处理
        handleMethod(clz, meta, methods, useReflectasm);
        //校验字段信息
        if (DBObject.class.isAssignableFrom(clz)) {
            //校验字段是否存在
            checkDBField(meta);
            //检查级联字段
            checkDBCascadeField(meta);
        }
        return meta;
    }

    /**
     * @param clz
     * @param subcls
     * @param meta
     */
    private static void handleClass(Class<?> clz, Class<?>[] subcls, TableMapping meta) {
        meta.setThisType(clz);
        Entity entity = clz.getAnnotation(Entity.class);
        Table table = clz.getAnnotation(Table.class);
        SqlResultSetMapping sqlResultSetMapping = clz.getAnnotation(SqlResultSetMapping.class);
        SqlResultSetMappings sqlResultSetMappings = clz.getAnnotation(SqlResultSetMappings.class);
        Comment tableComment = clz.getAnnotation(Comment.class);
        TableMeta tableMeta = clz.getAnnotation(TableMeta.class);
        if (tableComment != null && StringUtils.isNotBlank(tableComment.value())) {
            meta.setComment(tableComment.value());
        }
        if (tableMeta != null && ArrayUtils.isNotEmpty(tableMeta.value())) {
            meta.setTableMetaMap(new HashMap<>());
            for (Meta m : tableMeta.value()) {
                meta.getTableMetaMap().put(m.key(), m.value());
            }
        }
        EntityListenerManager.scan(clz);//EntityListener注解处理

        String defaultTableName = clz.getSimpleName();
        if (entity != null) {
            meta.setTableName(StringUtils.isNotBlank(entity.name()) ? entity.name() : defaultTableName);
        }
        if (table != null) {
            meta.setTable(table);
            meta.setSchema(table.schema());
            meta.setCatalog(table.catalog());
            if (StringUtils.isNotBlank(table.name())) {
                meta.setTableName(table.name());
            }
            if (StringUtils.isBlank(meta.getTableName())) {
                meta.setTableName(defaultTableName);
            }
//            if (table.indexes().length > 0) {
//                meta.setIndexs(Arrays.asList(table.indexes()));
//            }
//            if (table.uniqueConstraints().length > 0) {
//                meta.setUniques(Arrays.asList(table.uniqueConstraints()));
//            }
        }

        if (sqlResultSetMapping != null) {
            SQL_RESULT_SET_MAPPING_MAP.put(sqlResultSetMapping.name(), sqlResultSetMapping);
        }
        if (sqlResultSetMappings != null && sqlResultSetMappings.value().length > 0) {
            for (SqlResultSetMapping mapping : sqlResultSetMappings.value()) {
                SQL_RESULT_SET_MAPPING_MAP.put(mapping.name(), mapping);
            }
        }

//        List<String> enumFields = new ArrayList<>();
//        List<String> enumCascadeFields = new ArrayList<>();
        // 解析数据库对应的枚举类
        if (subcls != null && subcls.length > 0) {
            for (int i = 0; i < subcls.length; i++) {
                Class<?> cls = subcls[i];
                if (/* Modifier.isStatic(cls.getModifiers()) && */cls.isEnum() && DBField.class.isAssignableFrom(cls)) {
                    Class<? extends Enum> sub = cls.asSubclass(Enum.class);
                    Enum[] enumConstants = sub.getEnumConstants();
                    for (int j = 0; j < enumConstants.length; j++) {
                        Enum<?> f = enumConstants[j];
                        DBField field = (DBField) f;
//                        enumFields.add(field.name());// 父类的放在后面，子类的放在前面。
                        meta.getFields().put(field.name(), field);
                    }
                } else if (/* Modifier.isStatic(cls.getModifiers()) && */cls.isEnum() && DBCascadeField.class.isAssignableFrom(cls)) {
                    Class<? extends Enum> sub = cls.asSubclass(Enum.class);
                    Enum[] enumConstants = sub.getEnumConstants();
                    for (int j = 0; j < enumConstants.length; j++) {
                        Enum<?> f = enumConstants[j];
                        DBCascadeField field = (DBCascadeField) f;
//                        enumCascadeFields.add(field.name());
//                        enumFields.add(field.name());// 父类的放在后面，子类的放在前面。
                        if (meta.getCascadeFields().isEmpty()) {
                            meta.setCascadeFields(new LinkedHashMap<>());
                        }
                        meta.getCascadeFields().put(field.name(), field);
                    }
                }
            }
        }
    }

    /**
     * @param meta
     * @param fields
     */
    private static void handleField(TableMapping meta, List<Field> fields) {
        // 解析字段 不支持方法上加注解
        if (CollectionUtils.isNotEmpty(fields)) {
            for (Iterator<Field> it = fields.iterator(); it.hasNext(); ) {
                Field f = it.next();
                if (Modifier.isStatic(f.getModifiers()) || Modifier.isTransient(f.getModifiers())) {
                    it.remove();
                }
            }
            for (Field f : fields) {
                //JPA注解处理
                Id id = f.getAnnotation(Id.class);
                GeneratedValue gv = f.getAnnotation(GeneratedValue.class);
                Column col = f.getAnnotation(Column.class);
                Temporal temporal = f.getAnnotation(Temporal.class);
                Enumerated enumerated = f.getAnnotation(Enumerated.class);
                Lob lob = f.getAnnotation(Lob.class);
                Transient trans = f.getAnnotation(Transient.class);
                ManyToMany mtm = f.getAnnotation(ManyToMany.class);
                ManyToOne mto = f.getAnnotation(ManyToOne.class);
                OneToMany otm = f.getAnnotation(OneToMany.class);
                OneToOne oto = f.getAnnotation(OneToOne.class);
                JoinColumn jc = f.getAnnotation(JoinColumn.class);
                JoinColumns jcs = f.getAnnotation(JoinColumns.class);
                JoinTable jt = f.getAnnotation(JoinTable.class);
                SequenceGenerator sequenceGenerator = f.getAnnotation(SequenceGenerator.class);
                TableGenerator tableGenerator = f.getAnnotation(TableGenerator.class);
                OrderBy orderBy = f.getAnnotation(OrderBy.class);
                OrderColumn orderColumn = f.getAnnotation(OrderColumn.class);
                Version version = f.getAnnotation(Version.class);
                Convert convert = f.getAnnotation(Convert.class);
                ElementCollection ec = f.getAnnotation(ElementCollection.class);
                CollectionTable ct = f.getAnnotation(CollectionTable.class);
                //jpa map注解
                MapKey mapKey = f.getAnnotation(MapKey.class);
                MapKeyClass mapKeyClass = f.getAnnotation(MapKeyClass.class);
                MapKeyColumn mapKeyColumn = f.getAnnotation(MapKeyColumn.class);
                MapKeyEnumerated mapKeyEnumerated = f.getAnnotation(MapKeyEnumerated.class);
                MapKeyJoinColumn mapKeyJoinColumn = f.getAnnotation(MapKeyJoinColumn.class);
                MapKeyJoinColumns mapKeyJoinColumns = f.getAnnotation(MapKeyJoinColumns.class);

                //自定义注解(非JAP标准)
                ColumnInfo cd = f.getAnnotation(ColumnInfo.class);
                SavedDefaultValue uv = f.getAnnotation(SavedDefaultValue.class);
                Comment comment = f.getAnnotation(Comment.class);
                Type type = f.getAnnotation(Type.class);
                FetchDBField fetchDBField = f.getAnnotation(FetchDBField.class);
                UniqueKeyGenerator keyGenerator = f.getAnnotation(UniqueKeyGenerator.class);
                Tail tail = f.getAnnotation(Tail.class);
                CreatedDate createdDate = f.getAnnotation(CreatedDate.class);
                LastModifiedDate lastModifiedDate = f.getAnnotation(LastModifiedDate.class);

                // if (enumFields.contains(f.getName())) {
                ColumnMapping cm = new ColumnMapping();
                cm.setMeta(meta);
                cm.setFieldName(f.getName());
                cm.setClz(f.getType());
                cm.setType(type);
                if (comment != null && StringUtils.isNotBlank(comment.value())) {
                    cm.setComment(comment.value());
                }
                cm.setFetchDBField(fetchDBField);
                cm.setSaveDefaultValue(uv);
                cm.setUniqueKeyGenerator(keyGenerator);
                cm.setCreatedDate(createdDate != null);
                cm.setLastModifiedDate(lastModifiedDate != null);

                cm.setManyToMany(mtm);
                cm.setManyToOne(mto);
                cm.setOneToMany(otm);
                cm.setJoinColumn(jc);
                cm.setJoinColumns(jcs);
                cm.setJoinTable(jt);
                cm.setGv(gv);
                cm.setType(type);
                cm.setJpaTransient(trans);
                cm.setVersion(version != null);
                cm.setEnumerated(enumerated);
                cm.setSequenceGenerator(sequenceGenerator);
                cm.setConvert(convert);
                cm.setCollectionTable(ct);
                cm.setElementCollection(ec);
                cm.setOrderBy(orderBy);
                cm.setOrderColumn(orderColumn);
                cm.setMapKey(mapKey);
                cm.setMapKeyClass(mapKeyClass);
                cm.setMapKeyColumn(mapKeyColumn);
                cm.setMapKeyEnumerated(mapKeyEnumerated);
                cm.setMapKeyJoinColumn(mapKeyJoinColumn);
                cm.setMapKeyJoinColumns(mapKeyJoinColumns);

                if (cd != null) {
                    cm.setColumnInfo(cd);
                    if (cd.logicDelete()){
                        meta.setLogicDeleteField(cm);
                    }
                }

                if (cm.getUniqueKeyGenerator() != null) {
                    try {
                        cm.setIdentifierGenerator(cm.getUniqueKeyGenerator().targetClass().getDeclaredConstructor().newInstance());
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
                if (tail != null) {
                    cm.setTail(true);
                    if (meta.getTailField() != null) {
                        throw new SmallOrmException("tail注解只能有一个");
                    }
                    if (cm.getClz() != Map.class) {
                        throw new SmallOrmException("tail注解只能使用在Map中");
                    }
                    meta.setTailField(cm);
                }


                if (oto != null) {
                    cm.setOneToOne(oto);
                }

                if (id != null) {
                    cm.setPk(true);
                    if (meta.getPkFields().isEmpty()) {
                        meta.setPkFields(new ArrayList<>());
                    }
                    meta.getPkFields().add(cm);
                }
                if (createdDate != null || lastModifiedDate != null) {
                    if (meta.getSpecialFields().isEmpty()) {
                        meta.setSpecialFields(new ArrayList<>());
                    }
                    meta.getSpecialFields().add(cm);
                }
                String columnName = f.getName();
                if (col != null) {
                    cm.setColumn(col);
                    if (StringUtils.isNotBlank(col.name())) {
                        columnName = col.name();
                    }
                    cm.setNotInsert(!col.insertable());
                    cm.setNotUpdate(!col.updatable());
                }
                cm.setRawColumnName(columnName);
                cm.setUpperColumnName(cm.getRawColumnName().toUpperCase());
                cm.setLowerColumnName(cm.getRawColumnName().toLowerCase());
                if (lob != null) {
                    cm.setLob(true);
                }
                if (temporal != null) {
                    cm.setTemporal(temporal);
                }
                // 设置泛型
                PropertyHold ph = new PropertyHold();
                ph.setField(f);
                ph.setName(f.getName());// -- 设置泛型原始类型
                if (Collection.class.isAssignableFrom(cm.getClz()) || Map.class.isAssignableFrom(cm.getClz())) {
                    java.lang.reflect.Type[] types = ReflectionExtends.getParameterizedType(f);
                    if (types != null && types.length > 0) {
                        Class[] classes = new Class[types.length];
                        for (int i = 0; i < types.length; i++) {
                            classes[i] = (Class) types[i];
                        }
                        ph.setRawTypes(classes);
                    }
                }
                cm.setFieldAccessor(ph);
                //设置DBField
                cm.setField(meta.getFields().get(f.getName()));
                if (!meta.getCascadeFields().isEmpty()) {
                    cm.setCascadeField(meta.getCascadeFields().get(f.getName()));
                }

                cm.setHandler(Jdbcs.getBean2DBMappingType(cm));
                //设置jdbc sql type
                Jdbcs.setJdbcSqlType(cm);
                cm.setColumnDef(new ColumnDBType(cm));
                meta.getColumnFieldMap().put(cm.getRawColumnName(), cm);
                meta.getMetaFields().add(cm);
                meta.getMetaFieldMap().put(f.getName(), cm);
                DBField field = meta.getFields().get(f.getName());
                if (field != null) {
                    meta.getSchemaMap().put(field, cm);
                    meta.getSchemas().add(cm);
                    if (useDBField2Column) {
                        dbField2Column.put(field, cm);
                    }
                    if (cm.isVersion()) {
                        if (meta.getVersionMap().isEmpty()) {
                            meta.setVersionMap(new LinkedHashMap<>());
                        }
                        meta.getVersionMap().put(field, cm);
                    }
                }
                // }

            }
        }
    }

    /**
     * @param clz
     * @param meta
     * @param methods
     * @param useReflectasm
     */
    private static void handleMethod(Class<?> clz, TableMapping meta, Method[] methods, boolean useReflectasm) {
        MethodAccess methodAccess = null;
        if (useReflectasm) {
            methodAccess = MethodAccess.get(clz);
            meta.setMethodAccess(methodAccess);
            meta.setConstructorAccess(ConstructorAccess.get(clz));
        }

        // 不支持从方法写注解
        if (ArrayUtils.isNotEmpty(methods)) {
            for (ColumnMapping cm : meta.getMetaFields()) {
                String fieldName = cm.getFieldName();
                String uppercaseMethodName = StringUtils.upperCase(String.valueOf(fieldName.charAt(0))) + fieldName.substring(1);
                String setMethodName = "set" + uppercaseMethodName;
                String getMethodName = "";
                if (cm.getClz() == boolean.class) {
                    getMethodName = "is" + uppercaseMethodName;
                } else {
                    getMethodName = "get" + uppercaseMethodName;
                }
                for (int i = 0; i < methods.length; i++) {
                    Method m = methods[i];
                    if (setMethodName.equals(m.getName()) && m.getParameterCount() == 1) {//桥接方法?
                        cm.getFieldAccessor().setSetter(m);
                        if (useReflectasm) {
                            cm.getFieldAccessor().setReflectasmSetterIndex(methodAccess.getIndex(setMethodName));
                        }
                    }
                    if (getMethodName.equals(m.getName()) && m.getParameterCount() == 0) {//桥接方法?
                        cm.getFieldAccessor().setGetter(m);
                        if (useReflectasm) {
                            cm.getFieldAccessor().setReflectasmGetterIndex(methodAccess.getIndex(getMethodName));
                        }
                    }
                    if (m.getName().equals("push")) {
                        meta.setExistPushMethod(true);
                    }
                    if (m.getName().equals("pull")) {
                        meta.setExistPullMethod(true);
                    }
                }
                if (cm.getField() != null && (cm.getFieldAccessor() == null
                        || cm.getFieldAccessor().getSetter() == null || cm.getFieldAccessor().getGetter() == null)) {
                    throw new SmallOrmException("字段[" + cm.getFieldName() + "--->>" + cm.getMeta().getThisType() + "]的set,get或is方法不全!");
                }
            }
        }
    }

    /**
     * 校验字段是否存在
     * @param meta
     */
    private static void checkDBField(TableMapping meta) {
        //从列中查找枚举
        for (ColumnMapping cm : meta.getMetaFields()) {
            if (cm.getColumn() != null || cm.isPk() || cm.getTemporal() != null || cm.getEnumerated() != null || cm.isVersion()) {
                boolean exist = true;
                if (meta.getFields().get(cm.getFieldName()) == null) {
                    exist = false;
                }
                if (!exist) {
                    throw new SmallOrmException("字段[" + cm.getFieldName() + "--->>" + cm.getMeta().getThisType() + "]在类中中已定义,但未找到该字段的枚举定义!");
                }
            }
        }
        //从枚举中查找列
        for (Entry<String, DBField> entry : meta.getFields().entrySet()) {
            ColumnMapping cm = meta.getSchemaMap().get(entry.getValue());
            if (cm == null) {
                throw new SmallOrmException("字段[" + entry.getValue().name() + "--->>" + entry.getValue().getClass() + "]在枚举中已定义,但未找到该字段!");
            }
        }
    }

    /**
     * 校验级联字段是否存在
     * @param meta
     */
    private static void checkDBCascadeField(TableMapping meta) {
        //从列中查找枚举
        for (ColumnMapping cm : meta.getMetaFields()) {
            if (cm.isCascade()) {
                boolean exist = false;
                for (Entry<String, DBCascadeField> entry : meta.getCascadeFields().entrySet()) {
                    if (Objects.equals(entry.getValue(), cm.getCascadeField())) {
                        exist = true;
                    }
                }
                if (!exist) {
                    throw new SmallOrmException("字段[" + cm.getFieldName() + "--->>" + cm.getMeta().getThisType() + "]在类中中已定义,但未找到该字段的级联定义!");
                }
            }
        }
        //从枚举中查找列
        for (Entry<String, DBCascadeField> entry : meta.getCascadeFields().entrySet()) {
            boolean f = false;
            for (ColumnMapping cm : meta.getMetaFields()) {
                if (cm.isCascade() && Objects.equals(cm.getCascadeField(), entry.getValue())) {
                    f = true;
                }
            }
            if (!f) {
                throw new SmallOrmException("字段[" + entry.getKey() + "--->>" + meta.getThisType() + "]在类中中已定义,但未找到该字段的级联定义!");
            }
        }
    }

    /**
     * 处理级联
     */
    public static void cascade(TableMapping tm) {
        for (ColumnMapping cm : tm.getMetaFields()) {
            if (cm.getManyToMany() != null || cm.getOneToMany() != null || cm.getManyToOne() != null || cm.getOneToOne() != null) {
                cascade(tm, cm);
            }
        }
    }


    public static void cascade(TableMapping tm, ColumnMapping cm) {
        //TODO 此处待处理,级联需要
        CascadeConfig cc = CascadeUtils.doCascade((Class<? extends DBObject>) tm.getThisType(), cm);
        cm.setCascadeConfig(cc);
    }

    /**
     * 级联关系,数据类型一致性校验缺乏.
     * @param tm
     */
    public static void checkCascade(TableMapping tm) {
        for (ColumnMapping cm : tm.getMetaFields()) {
            CascadeConfig cc = cm.getCascadeConfig();
            if (cc != null) {
                if (cc.getFromToColumns() != null) {
                    for (Map.Entry<ColumnMapping, ColumnMapping> entry : cc.getFromToColumns().entrySet()) {
                        Class<?> keyClz = entry.getKey().getClz();
                        Class<?> valueClz = entry.getValue().getClz();
                        keyClz = JavaTypeUtils.changePrimitiveToWrapperType(keyClz);
                        valueClz = JavaTypeUtils.changePrimitiveToWrapperType(valueClz);
                        if (keyClz != valueClz) {
                            throw new SmallOrmException(entry.getKey().meta.getThisType().getName() + " 级联字段 " + entry.getKey().getFieldName() + "  --->> " +
                                    entry.getValue().meta.getThisType().getName() + " 级联字段 " + entry.getValue().getFieldName() + " 数据类型不一致!");
                        }
                    }
                }
                if (cc.getMiddleTableColumns() != null) {
                    //TODO
                }
            }
        }
    }

    /**
     * 检查是否执行了增强
     * @param type
     */
    private static void assertEnhanced(Class<? extends IEntity> type, SmallEntity ee) {
        if (ee != null && !ee.checkEnhanced()) {
            return;
        }
        String resourceName = type.getName().replace('.', '/') + ".class";
        URL url = type.getClassLoader().getResource(resourceName);
        if (url == null) {
            logger.warn("The source of class " + type + " not found, skip enhanced-check.");
            return;
        }
        byte[] data;
        try {
            data = IOUtils.toByteArray(url);
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
        ClassReader cr = new ClassReader(data);

        final AtomicBoolean checkd = new AtomicBoolean(false);
        cr.accept(new ClassVisitor(SpringAsmInfo.ASM_VERSION) {
            public void visitAttribute(Attribute attr) {
                if (IEntityEnhancer.ENHANCE_HEADER.equals(attr.type)) {
                    checkd.set(true);
                }
                super.visitAttribute(attr);
            }
        }, ClassReader.SKIP_CODE);
        if (!checkd.get()) {
            throw new EntityNotEnhancedException(type.getName());
        }
    }

    /**
     * @param f
     * @return
     */
    public static ColumnMapping getColumnMapping(DBField f, String clzName) {
        ColumnMapping cm = dbField2Column.get(f);
        if (cm == null) {
            try {
                Class<?> clz = Class.forName(clzName);
                TableMapping tm = MetaHolder.initData(clz, checkEnhancement);
                dbField2Column.putAll(tm.getSchemaMap());
                cm = dbField2Column.get(f);
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        }
        return cm;
    }

    public static ColumnMapping getColumnMapping(DBField field) {
        Class<? extends DBField> clz = field.getClass();
        String name = clz.getName().substring(0, clz.getName().lastIndexOf("$"));
        return getColumnMapping(field, name);
    }

    public static ColumnMapping getColumnMappingDirect(DBField field) {
        return dbField2Column.get(field);
    }

    public static Map<Class<?>, TableMapping> getAllClass() {
        Map<Class<?>, TableMapping> map = new HashMap<>(pool);
        return Collections.unmodifiableMap(map);
    }

    public static Map<Class<?>, TableMapping> getAllSoftPoolClass() {
        Map<Class<?>, TableMapping> map = new HashMap<>(softPool);
        return Collections.unmodifiableMap(map);
    }

    /**
     * 获取列
     * @param clz
     * @param field
     * @return
     */
    public static ColumnMapping getColumnMapping(Class<? extends DBObject> clz, DBField field) {
        TableMapping tm = getMeta(clz);
        Map<DBField, ColumnMapping> map = tm.getSchemaMap();
        return map.get(field);
    }

    public static void clear() {
        pool.clear();
        softPool.clear();
    }

    public static void remove(Class<?> clz) {
        pool.remove(clz);
        softPool.remove(clz);
    }
}
